package com.maple.retry.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.maple.retry.dao.RetryTaskDAO;
import com.maple.retry.dao.RetryTaskHistoryDAO;
import com.maple.retry.entity.RetryTaskDO;
import com.maple.retry.entity.RetryTaskHistoryDO;
import com.maple.retry.retrytask.convertor.RetryTaskInfoConvertor;
import com.maple.retry.retrytask.enums.RetryTaskStatusEnum;
import com.maple.retry.retrytask.model.RetryTaskInfo;
import com.maple.retry.service.RetryTaskService;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Description RetryTaskServiceImpl
 * @Date 2020/4/24 7:41
 * @Created by 王弘博
 */
@Service
public class RetryTaskServiceImpl extends ServiceImpl<RetryTaskDAO, RetryTaskDO> implements RetryTaskService {

    @Resource
    private RetryTaskDAO retryTaskDAO;

    @Resource
    private RetryTaskHistoryDAO retryTaskHistoryDAO;

    @Override
    public void create(RetryTaskInfo taskInfo, long delay) {

        taskInfo.setGmtCreate(new Date());
        taskInfo.setGmtModified(new Date());
        taskInfo.setScheduleTime(new Date(new Date().getTime() + delay));

        RetryTaskDO retryTaskDO = RetryTaskInfoConvertor.convert2RetryTaskDO(taskInfo);

        retryTaskDAO.insert(retryTaskDO);
    }

    @Override
    public void archive(RetryTaskInfo taskInfo) {

        taskInfo.setGmtCreate(new Date());
        taskInfo.setGmtModified(new Date());

        RetryTaskHistoryDO taskHistoryDO = RetryTaskInfoConvertor.convert2RetryTaskHistoryDO(taskInfo);

        retryTaskHistoryDAO.insert(taskHistoryDO);
    }

    @Override
    public RetryTaskInfo loadByTaskId(String taskId) {
        return null;
    }

    @Override
    public RetryTaskInfo loadArchivedTaskByBizInfo(String bizId, String bizType) {

        RetryTaskHistoryDO retryTaskHistoryDO = retryTaskHistoryDAO.selectOne(new QueryWrapper<RetryTaskHistoryDO>().eq("biz_id", bizId).eq("biz_type", bizType));

        RetryTaskInfo retryTaskInfo = RetryTaskInfoConvertor.convert2RetryTaskInfo(retryTaskHistoryDO);

        return retryTaskInfo;
    }

    @Override
    public List<RetryTaskInfo> loadScheduleTasks(String bizType, Integer loadSize) {
        return null;
    }

    @Override
    public RetryTaskInfo lockByTaskId(String taskId) {
        RetryTaskDO taskDO = retryTaskDAO.selectOne(new QueryWrapper<RetryTaskDO>().eq("task_id", taskId).last("FOR UPDATE"));
        RetryTaskInfo taskInfo = RetryTaskInfoConvertor.convert2RetryTaskInfo(taskDO);
        return taskInfo;
    }

    @Override
    public RetryTaskInfo lockByBizInfo(String bizId, String bizType) {
        return null;
    }

    @Override
    public void updateRetryInfo(String taskId, long delay) {

    }

    @Override
    public void drop(String taskId) {
        retryTaskDAO.delete(new QueryWrapper<RetryTaskDO>().eq("task_id", taskId));
    }

    @Override
    public void updateStatusByTaskId(RetryTaskInfo taskInfo, RetryTaskStatusEnum status) {

        Assert.notNull(taskInfo, "RetryTaskInfo is null");

        LambdaUpdateWrapper<RetryTaskDO> wrapper = new LambdaUpdateWrapper<>();

        wrapper.eq(RetryTaskDO::getTaskId, taskInfo.getId()).
                set(RetryTaskDO::getStatus, status.getCode()).
                set(RetryTaskDO::getGmtModified, new Date());

        retryTaskDAO.update(null, wrapper);
    }

    @Override
    public void updateRetryAndStatusByTaskId(RetryTaskInfo taskInfo, RetryTaskStatusEnum status, long delay) {

        Assert.notNull(taskInfo, "RetryTaskInfo is null");

        LambdaUpdateWrapper<RetryTaskDO> wrapper = new LambdaUpdateWrapper<>();

        wrapper.eq(RetryTaskDO::getTaskId, taskInfo.getId()).
                set(RetryTaskDO::getRetryNo, taskInfo.getRetryNo()).
                set(RetryTaskDO::getStatus, status.getCode()).
                set(RetryTaskDO::getGmtModified, new Date()).
                set(RetryTaskDO::getScheduleTime, new Date(new Date().getTime() + delay));

        retryTaskDAO.update(null, wrapper);
    }

    @Override
    public List<RetryTaskInfo> loadScheduleTasksByStatus(String bizType, Integer loadSize, RetryTaskStatusEnum status) {

        List<RetryTaskInfo> taskInfos = new ArrayList<>();

        List<RetryTaskDO> taskDOs = retryTaskDAO.selectList(new QueryWrapper<RetryTaskDO>().eq("biz_type", bizType).le("schedule_time", new Date()).eq("status", status.getCode()).last("limit 0," + loadSize));

        for (RetryTaskDO taskDO : taskDOs) {
            RetryTaskInfo taskInfo = RetryTaskInfoConvertor.convert2RetryTaskInfo(taskDO);
            taskInfos.add(taskInfo);
        }
        return taskInfos;
    }
}
